using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using Styx;
using Styx.Combat.CombatRoutine;
using Styx.Helpers;
using Styx.Logic;
using Styx.Logic.Combat;
using Styx.Logic.Pathing;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

using Natfoth.Helpers;
using Styx.WoWInternals.World;
using TreeSharp;
using Action = TreeSharp.Action;

namespace Natfoth.Classes
{
    public class Priest
    {
        private static LocalPlayer Me { get { return ObjectManager.Me; } }
        private static WoWUnit Targ { get { return ObjectManager.Me.CurrentTarget; } }
        public static string Version = "0.0.4";
        public static string Name = "Akatosh Priest";
        public static WoWUnit LastHealedUnit;

        public static Composite PriestRestBehavior()
        {
            return new PrioritySelector(   

                    new Decorator(akatosh => Me.IsCasting && Me.CastingSpell.Name == "Flash Heal" && Me.HealthPercent > 95,
                        new Action(akatosh => Spell.StopCasting())),


                    //new NeedToDispersionRest(new DispersionRest()),

                    Lib.BuffSelf("Dispersion", akatosh => Me.ManaPercent <= PriestSettings.RestMana),

                    // Heal (Flash Heal) before drinking
                    Lib.Cast("Flash Heal", akatosh => Me.HealthPercent <= PriestSettings.RestHealth && !Me.IsInInstance && !Me.IsCasting),

                    Lib.RestBehaviour()

                    // Eat and Drink
                    //new NeedToEatDrink(new EatDrink()),

                    // Shadowform
                   // Lib.BuffSelf("Shadowfom", akatosh => !Self.IsBuffOnMe("Dispersion") && Self.IsHealthPercentAbove(PriestSettings.FlashHealHealth) && Self.IsHealthPercentAbove(PriestSettings.RenewHealth) && !Self.IsBuffOnMe(15473, Self.AuraCheck.AllAuras))
                    //new NeedToShadowform(new Shadowform())
            );
        }

        #region ShadowPriest

        public static Composite ShadowPriestCombat()
        {

            return new PrioritySelector(

                    //new NeedToShadowform(new Shadowform()),

                    Lib.BuffSelf("Shadowfom", akatosh => !Self.IsBuffOnMe("Dispersion") && Self.IsHealthPercentAbove(PriestSettings.FlashHealHealth) && Self.IsHealthPercentAbove(PriestSettings.RenewHealth) && !Self.IsBuffOnMe(15473, Self.AuraCheck.AllAuras)),

                    //new Decorator(ret => !Me.GotTarget && Me.GotAlivePet && Me.Pet.GotTarget, new Action(ret => Me.Pet.CurrentTarget.Target())),

                    new Lib.NeedToRetarget(new Lib.Retarget()),

                    //new Lib.NeedToCheckCombatTimer(new Lib.CheckCombatTimer()),

                    new Lib.NeedToLOSCheck(new Lib.LOSCheck()),

                    new Lib.NeedToAutoAttack(new Lib.AutoAttack()),

                    new Decorator(akatosh => Targ == null,
                        new Action(akatosh => RunStatus.Success)),

                    new Decorator(akatosh => Targ != null && !Me.IsFacing(Targ),
                        new Action(akatosh => Lib.FaceTarget())),

                    new Decorator(akatosh => Targ != null && Targ.Distance < 35 && Me.IsMoving,
                        new Action(akatosh => Navigator.PlayerMover.MoveStop())),

                    new Decorator(akatosh => Me.IsCasting && Me.CastingSpell.Name == "Flash Heal" && Me.HealthPercent > 95,
                        new Action(akatosh => Spell.StopCasting())),

                    Lib.BuffSelf("Dispersion", akatosh => Me.ManaPercent <= PriestSettings.DispersionMana),

                    new NeedToShadowWordDeath(new ShadowWordDeath()),

                    Lib.Cast("Dispersion", akatosh => Self.IsBuffOnMe("Dispersion") && Me.ManaPercent > PriestSettings.DispersionMana),
                    Lib.Cast("Silence", akatosh => Target.CanDebuffTarget("Silence") && Targ.IsCasting),
                    Lib.Cast("Shadowfiend", akatosh => Target.IsElite && Targ.HealthPercent > 30 && Utils.Adds && Me.ManaPercent > PriestSettings.ShadowfiendMana),

                    new NeedToShackle(new Shackle()),
                    new NeedToArchangle(new Archangle()),

                    Lib.Cast("Power Word: Barrier", akatosh => CLC.ResultOK(PriestSettings.PowerWordBarrier)),
                    Lib.Cast("Power Infusion", akatosh => Self.CanBuffMe("Power Infusion") && CLC.ResultOK(PriestSettings.PowerInfusion)),
                    new NeedToHolyNova(new HolyNova()),

                    Lib.BuffSelf("Power Word: Shield", akatosh => StyxWoW.Me.HealthPercent < 50 && StyxWoW.Me.CurrentTarget.HealthPercent > 30 && !StyxWoW.Me.HasAura("Weakened Soul", 0)),

                    Lib.Cast("Renew", akatosh => Me.HealthPercent < 50 && !Me.HasAura("Renew") && !Me.IsInInstance),
                    Lib.Cast("Flash Heal", akatosh => Me.HealthPercent < 40 && !Me.IsInInstance && !Utils.IsBattleground),

                    Lib.Cast("Holy Fire", akatosh => CLC.ResultOK(PriestSettings.HolyFire) && Target.IsElite && Targ.HealthPercent > 30 && Utils.Adds && Target.CanDebuffTarget("Holy Fire")),
                    
                    Lib.Buff("Vampiric Touch", akatosh => Target.IsElite),
                    Lib.Buff("Devouring Plague", akatosh => !StyxWoW.Me.CurrentTarget.IsMechanical),
                    Lib.Buff("Shadow Word: Pain", akatosh => (!Targ.HasAura("Vampiric Touch") && !Targ.HasAura("Devouring Plague")) || StyxWoW.Me.IsInInstance || StyxWoW.Me.CurrentTarget.IsPlayer),
                    
                    
                    Lib.Cast("Psychic Scream", akatosh => CLC.ResultOK(PriestSettings.PsychicScream) && !Target.IsDistanceMoreThan(8) && (!Lib.PriestDedicatedHealerCheck() && !PriestSettings.PsychicScream.Contains("when in battleground"))),
                    Lib.Cast("Mind Sear", akatosh => !PriestSettings.MindSear.Contains("never") && Me.IsInInstance && CLC.ResultOK(PriestSettings.MindSear) && Me.IsInInstance && RAF.PartyTankRole != null && (Utils.CountOfAddsInRange(10, RAF.PartyTankRole.Location) >= 3 && Spell.CanCast("Mind Sear"))),
                    Lib.Cast("Mind Blast", akatosh => CLC.ResultOK(PriestSettings.MindBlast)),
                    Lib.Cast("Mind Spike"),
                    Lib.Cast("Chastise", akatosh => CLC.ResultOK(PriestSettings.Chastise)),
                    Lib.Cast("Penance", akatosh => CLC.ResultOK(PriestSettings.Penance)),
                    Lib.Cast("Smite", akatosh => !Lib.HasBuff("Shadowform") && CLC.ResultOK(PriestSettings.Smite)),
                    Lib.Cast("Mind Flay", akatosh => CLC.ResultOK(PriestSettings.MindFlay)),
                    Lib.BuffSelf("Fade", akatosh => Me.IsInParty && Utils.CountOfMobsAttackingPlayer(Me.Guid) > 0),

                    Lib.Cast("Shoot", akatosh => Me.ManaPercent < 10),

                    Lib.CreateMoveToTargetBehavior(true, 35f),

                    new Action(ret => ObjectManager.Update())
             );
        }

        public static Composite ShadowPriestCombatBuffs()
        {
            return new PrioritySelector(

                   Lib.Cast("Inner Fire", akatosh => !Lib.HasBuff("Inner Fire"))
            );
        }

        public static bool ShadowPriestNeedBuffs()
        {
            if (!Lib.HasBuff("Inner Fire"))
                return true;

            if (!Lib.HasBuff("Power Word: Fortitude"))
                return true;

            return false;
        }

        public static Composite ShadowPriestBuffs()
        {
            return new PrioritySelector(

                   Lib.Cast("Inner Fire", akatosh => !Lib.HasBuff("Inner Fire")),
                   Lib.Cast("Power Word: Fortitude", akatosh => !Lib.HasBuff("Power Word: Fortitude"))
            );
        }

        public static Composite ShadowPriestPullBehavior()
        {
            return new PrioritySelector(

                new Lib.NeedToNavigatePath(new Lib.NavigatePath()),

                //new Lib.NeedToBlacklistPullTarget(new Lib.BlacklistPullTarget()),

                //new Lib.NeedToCheckPullTimer(new Lib.BlacklistPullTarget()),

                Lib.BuffSelf("Shadowfom", akatosh => !Self.IsBuffOnMe("Dispersion") && Self.IsHealthPercentAbove(PriestSettings.FlashHealHealth) && Self.IsHealthPercentAbove(PriestSettings.RenewHealth) && !Self.IsBuffOnMe(15473, Self.AuraCheck.AllAuras)),
                //new NeedToShadowform(new Shadowform()),

                new Decorator(akatosh => Me.Combat,
                              new Action(akatosh => RunStatus.Success)),


                new Lib.NeedToLOSCheck(new Lib.LOSCheck()),

                new Decorator(akatosh => Targ != null && !Me.IsFacing(Targ),
                              new Action(akatosh => Lib.FaceTarget())),

                new Decorator(akatosh => Targ != null && Targ.Distance < 35 && Me.IsMoving,
                        new Action(akatosh => Navigator.PlayerMover.MoveStop())),

                new Lib.NeedToAutoAttack(new Lib.AutoAttack()),

                new NeedToShieldPull(new ShieldPull()),

                new NeedToPullSpell(new PullSpell()),

                // Smite Pull
                new NeedToSmitePull(new SmitePull()),



                Lib.CreateMoveToTargetBehavior(true, 35f),
                

                new Action(ret => ObjectManager.Update())
            );
        }

        #endregion


        #region DiscPriest

        public static Composite DiscPriestCombat()
        {

            return new PrioritySelector(

                    //new NeedToShadowform(new Shadowform()),

                    new Lib.NeedToRetarget(new Lib.Retarget()),

                    //new Lib.NeedToCheckCombatTimer(new Lib.CheckCombatTimer()),

                    new Lib.NeedToLOSCheck(new Lib.LOSCheck()),

                    new Lib.NeedToAutoAttack(new Lib.AutoAttack()),

                    new Decorator(akatosh => Targ == null,
                        new Action(akatosh => RunStatus.Success)),

                    new Decorator(akatosh => Targ != null && !Me.IsFacing(Targ),
                        new Action(akatosh => Lib.FaceTarget())),

                    new Decorator(akatosh => Targ != null && Targ.Distance < 35 && Me.IsMoving,
                        new Action(akatosh => Navigator.PlayerMover.MoveStop())),



                    // Shadowfiend
                    new NeedToShadowfiend(new Shadowfiend()),

                    // Shackle
                    new NeedToShackle(new Shackle()),

                    new NeedToArchangle(new Archangle()),

                    new NeedToPowerWordBarrier(new PowerWordBarrier()),

                    new NeedToPowerInfusion(new PowerInfusion()),

                    new NeedToHolyNova(new HolyNova()),

                    new NeedToHolyFire(new HolyFire()),

                    new NeedToPsychicScream(new PsychicScream()),

                    new NeedToChastise(new Chastise()),

                    new NeedToPenance(new Penance()),

                    new NeedToChakra(new Chakra()),

                    new NeedToSmite(new Smite()),

                    new NeedToHymnOfHope(new HymnOfHope()),

                    new NeedToPartyHealer(new PartyHealer()),

                    new NeedToPartyHealerUHS(new PartyHealerUHS()),

                    new NeedToPartyDecurse(new PartyDecurse()),

                    new NeedToBouncePOM(new BouncePOM()),

                    new NeedToHealPets(new HealPets()),

                    new NeedToSmiteEvangelism(new SmiteEvangelism()),

                    new NeedToWandParty(new WandParty()),


                    Lib.Cast("Shoot", akatosh => Me.ManaPercent < 10),

                    Lib.CreateMoveToTargetBehavior(true, 35f),

                    new Action(ret => ObjectManager.Update())
             );
        }

        public static Composite DiscPriestCombatBuffs()
        {
            return new PrioritySelector(

                   Lib.Cast("Inner Fire", akatosh => !Lib.HasBuff("Inner Fire"))
            );
        }

        public static bool DiscPriestNeedBuffs()
        {
            if (!Lib.HasBuff("Inner Fire"))
                return true;

            if (!Lib.HasBuff("Power Word: Fortitude"))
                return true;

            return false;
        }

        public static Composite DiscPriestBuffs()
        {
            return new PrioritySelector(

                   Lib.Cast("Inner Fire", akatosh => !Lib.HasBuff("Inner Fire")),
                   Lib.Cast("Power Word: Fortitude", akatosh => !Lib.HasBuff("Power Word: Fortitude"))
            );
        }

        public static Composite DiscPriestPullBehavior()
        {
            return new PrioritySelector(

                new Lib.NeedToNavigatePath(new Lib.NavigatePath()),

                //new Lib.NeedToBlacklistPullTarget(new Lib.BlacklistPullTarget()),

                //new Lib.NeedToCheckPullTimer(new Lib.BlacklistPullTarget()),

                new Decorator(akatosh => Me.Combat,
                              new Action(akatosh => RunStatus.Success)),


                new Lib.NeedToLOSCheck(new Lib.LOSCheck()),

                new Decorator(akatosh => Targ != null && !Me.IsFacing(Targ),
                              new Action(akatosh => Lib.FaceTarget())),

                new Decorator(akatosh => Targ != null && Targ.Distance < 35 && Me.IsMoving,
                        new Action(akatosh => Navigator.PlayerMover.MoveStop())),

                new Lib.NeedToAutoAttack(new Lib.AutoAttack()),

                new NeedToShieldPull(new ShieldPull()),

                // Smite Pull
                new NeedToSmitePull(new SmitePull()),



                Lib.CreateMoveToTargetBehavior(true, 35f),


                new Action(ret => ObjectManager.Update())
            );
        }
        #endregion






        #region Dispersion Rest
        public class NeedToDispersionRest : Decorator
        {
            public NeedToDispersionRest(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Dispersion";

                if (Self.IsBuffOnMe(dpsSpell)) return true;

                //if () return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;


                return (Spell.CanCast(dpsSpell));
            }
        }

        public class DispersionRest : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Dispersion";
                if (Self.IsBuffOnMe(dpsSpell)) return RunStatus.Success;

                bool result = Spell.Cast(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion



        #region Rest Heal

        public class NeedToRestHeal : Decorator
        {
            public NeedToRestHeal(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string spellName = "Flash Heal";

                if (!Utils.CombatCheckOk(spellName, false)) return false;
                if (Self.IsHealthPercentAbove(PriestSettings.RestHealPercent)) return false;
                //if (!Timers.Expired("HealingSpells", PriestSettings.HealingSpellTimer)) return false;

                return (Spell.CanCast(spellName));
            }
        }

        public class RestHeal : Action
        {
            protected override RunStatus Run(object context)
            {
                const string spellName = "Flash Heal";
                bool result = Spell.Cast(spellName, Me);
                Utils.LagSleep();

                Utils.WaitWhileCasting(Utils.CastingBreak.HealthIsAbove, 60, Me);
                Timers.Reset("HealingSpells");
                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }

        #endregion

        #region Shadowform

        public class NeedToShadowform : Decorator
        {
            public NeedToShadowform(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Shadowform";

                if (PriestSettings.PartyHealWhen.Contains("dedicated healer") && (Me.IsInInstance || Utils.IsBattleground) && PriestSettings.PartyHealWhenSpec.Contains(ClassHelpers.Priest.ClassSpec.ToString())) return false;
                if (Self.IsBuffOnMe("Dispersion")) return false;
                if (!CLC.ResultOK(PriestSettings.Shadowform)) return false;
                if (Self.IsBuffOnMe(15473, Self.AuraCheck.AllAuras)) return false;

                // Make sure we don't need to heal ourself first
                if (!Self.IsHealthPercentAbove(PriestSettings.FlashHealHealth)) return false;
                if (!Self.IsHealthPercentAbove(PriestSettings.RenewHealth)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class Shadowform : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Shadowform";
                var result = Spell.Cast(dpsSpell);
                Utils.LagSleep();

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }

        #endregion

        #region Shackle
        public class NeedToShackle : Decorator
        {
            public NeedToShackle(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Shackle Undead";

                if (!CLC.ResultOK(PriestSettings.ShackleUndead)) return false;
                if (PriestSettings.PartyHealWhen.Contains("dedicated healer") && (Me.IsInInstance || Utils.IsBattleground) && PriestSettings.PartyHealWhenSpec.Contains(ClassHelpers.Priest.ClassSpec.ToString())) return false;
                if (!Utils.Adds) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (!ClassHelpers.Common.CanCrowdControlUnit(dpsSpell,30,WoWCreatureType.Undead)) return false;
                if (ClassHelpers.Common.GotCrowdControledUnit(dpsSpell,30) != null) return false;

                //if (!Self.CanBuffMe(dpsSpell)) return false;
                //if (!Target.CanDebuffTarget(dpsSpell)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class Shackle : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Shackle Undead";
                ClassHelpers.Common.CrowdControlUnit(dpsSpell, 30, WoWCreatureType.Undead);
                Utils.LagSleep();
                Utils.WaitWhileCasting();
                //bool result = Spell.Cast(dpsSpell);
                //Utils.LagSleep();
                //bool result = Target.IsDebuffOnTarget(dpsSpell);
                //bool result = Self.IsBuffOnMe(dpsSpell);););

                return RunStatus.Success; //: RunStatus.Failure;
            }
        }
        #endregion

        #region Pull Spell
        public class NeedToPullSpell : Decorator
        {
            public NeedToPullSpell(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                string dpsSpell = PriestSettings.PullSpell;

                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (!PriestSettings.LazyRaider.Contains("always"))
                {
                    if (Target.IsDistanceMoreThan(Spell.MaxDistance(PriestSettings.PullSpell)))
                    {
                        if (ObjectManager.Me.ZoneId == 4384)
                        
                        Movement.MoveTo((float)Spell.MaxDistance(PriestSettings.PullSpell) - 5);
                        Thread.Sleep(1500);
                        return false;
                    }


                    if (Targ.InLineOfSpellSight && Me.IsMoving)
                    {
                        Movement.StopMoving();
                        Utils.LagSleep();
                    }
                }
                if (Me.IsMoving) return false;

                if (SpellBlacklist.Contains(34914) && dpsSpell == "Vampiric Touch") return false;

                if (Spell.IsKnown(dpsSpell) && Spell.IsOnCooldown(dpsSpell)) return false;
                return (Spell.CanCast(dpsSpell));
            }
        }

        public class PullSpell : Action
        {
            protected override RunStatus Run(object context)
            {
                string dpsSpell = PriestSettings.PullSpell;

                if(dpsSpell == "Vampiric Touch")
                    SpellBlacklist.Add(34914, TimeSpan.FromSeconds(5));

                Target.Face();
                Utils.LagSleep();

                bool result = Spell.Cast(dpsSpell);
                Utils.LagSleep();
                Utils.WaitWhileCasting();

                if (dpsSpell == "Vampiric Touch") Timers.Reset("VampiricTouch");

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion


        #region Shield Pull
        public class NeedToShieldPull : Decorator
        {
            public NeedToShieldPull(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Power Word: Shield";

                if (!CLC.ResultOK(PriestSettings.PWSBeforePull)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (Self.IsBuffOnMe(6788, Self.AuraCheck.AllAuras)) return false;
                if (Self.IsBuffOnMe("Power Word: Shield")) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class ShieldPull : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Power Word: Shield";

                Spell.Cast(dpsSpell, Me);
                Utils.LagSleep();

                bool result = Self.IsBuffOnMe(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Smite Pull
        public class NeedToSmitePull : Decorator
        {
            public NeedToSmitePull(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Smite";

                if (Spell.IsKnown(PriestSettings.PullSpell) && !Spell.IsOnCooldown(PriestSettings.PullSpell)) return false;        // If you can cast the selected pull spell bail out here
                if (Spell.CanCast(PriestSettings.PullSpell) && !Spell.IsOnCooldown(PriestSettings.PullSpell)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (Me.IsMoving) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class SmitePull : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Smite";
                bool result = Spell.Cast(dpsSpell);
                Utils.LagSleep();

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        

        #region Shadow Word: Death
        public class NeedToShadowWordDeath : Decorator
        {
            public NeedToShadowWordDeath(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
               // const string dpsSpell = "Shadow Word: Death";

                ObjectManager.Update();
                if (PriestSettings.ShadowWordDeath.Contains("target < 25% health")) { if (Targ.HealthPercent > 25) return false; }
                else { if (!CLC.ResultOK(PriestSettings.ShadowWordDeath)) return false; }
                if (Spell.IsOnCooldown("Shadow Word: Death")) return false;
                if (!SpellManager.HasSpell(32379)) return false;
                

                // Stop casting and SWD them if they are not an elite!
                if (PriestSettings.ShadowWordDeath.Contains("target < 25% health") && (Me.IsCasting))
                {
                    if (Target.IsElite || Me.IsInInstance) return false;

                    Lib.LogGreenMessage("Inturrupting Spell Cast for SW:D");
                    Spell.StopCasting();
                    while (Spell.IsGCD) Thread.Sleep(250);
                }

                return (SpellManager.HasSpell(32379) && !Spell.IsOnCooldown("Shadow Word: Death"));
            }
        }

        public class ShadowWordDeath : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Shadow Word: Death";
                bool result = Spell.Cast(dpsSpell);
                Utils.LagSleep();

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Holy Nova
        public class NeedToHolyNova : Decorator
        {
            public NeedToHolyNova(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Holy Nova";

                if (PriestSettings.HolyNova.Contains("never")) return false;

                if (!PriestSettings.HolyNova.Contains("when in battleground"))
                    if (PriestSettings.PartyHealWhen.Contains("dedicated healer") && (Me.IsInInstance || Utils.IsBattleground) && PriestSettings.PartyHealWhenSpec.Contains(ClassHelpers.Priest.ClassSpec.ToString())) return false;

                if (!Utils.Adds) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;

                int count = Utils.CountOfAddsInRange(10, Me.Location);

                

                if (PriestSettings.HolyNova.Contains("3+ adds") && count < 3) return false;
                if (PriestSettings.HolyNova.Contains("4+ adds") && count < 4) return false;
                if (PriestSettings.HolyNova.Contains("5+ adds") && count < 5) return false;
                if (PriestSettings.HolyNova.Contains("6+ adds") && count < 6) return false;
                if (PriestSettings.HolyNova.Contains("7+ adds") && count < 7) return false;
                if (PriestSettings.HolyNova.Contains("8+ adds") && count < 8) return false;
                if (PriestSettings.HolyNova.Contains("9+ adds") && count < 9) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class HolyNova : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Holy Nova";
                bool result = Spell.Cast(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Combat Timer / Timeout
        public class NeedToCheckCombatTimer : Decorator
        {
            public NeedToCheckCombatTimer(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                if (Utils.IsBattleground) return false;
                if (!Me.GotTarget || Me.CurrentTarget.Dead) return false;
                if (Target.IsElite) return false;
                if (Targ.Name.Contains("Training Dummy")) return false;
                if (Me.IsInInstance) return false;

                return Target.CombatTimerExpired && Target.IsHealthPercentAbove(98);
            }
        }

        public class CheckCombatTimer : Action
        {
            protected override RunStatus Run(object context)
            {
                Utils.Log(string.Format("Combat with {0} is bugged, blacklisting and finding another target.", Me.CurrentTarget.Name), System.Drawing.Color.FromName("Red"));
                Target.BlackList(60);
                Utils.LagSleep();

                return RunStatus.Success;
            }
        }
        #endregion

        #region Shadowfiend
        public class NeedToShadowfiend : Decorator
        {
            public NeedToShadowfiend(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Shadowfiend";

                if (Self.IsPowerPercentAbove(PriestSettings.ShadowfiendMana)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (!Target.IsElite && !Target.IsHealthPercentAbove(30) && !Utils.Adds) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class Shadowfiend : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Shadowfiend";
                bool result = Spell.Cast(dpsSpell);
                Utils.LagSleep();
                Utils.WaitWhileCasting();
                while (Spell.IsGCD) Thread.Sleep(250);
                Spell.Cast("Shadow Word: Pain");

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Power Infusion
        public class NeedToPowerInfusion : Decorator
        {
            public NeedToPowerInfusion(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Power Infusion";

                if (!Self.IsPowerPercentAbove(PriestSettings.ReserveMana)) return false;
                if (!CLC.ResultOK(PriestSettings.PowerInfusion)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (!Self.CanBuffMe(dpsSpell)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class PowerInfusion : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Power Infusion";
                bool result = Spell.Cast(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Holy Fire
        public class NeedToHolyFire : Decorator
        {
            public NeedToHolyFire(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Holy Fire";

                if (!CLC.ResultOK(PriestSettings.HolyFire)) return false;
                if (!PriestSettings.HolyFire.Contains("when in battleground"))
                    if (PriestSettings.PartyHealWhen.Contains("dedicated healer") && (Me.IsInInstance || Utils.IsBattleground) && PriestSettings.PartyHealWhenSpec.Contains(ClassHelpers.Priest.ClassSpec.ToString())) return false;
                if (!Self.IsPowerPercentAbove(PriestSettings.ReserveMana)) return false;
                if (!Self.IsPowerPercentAbove(PriestSettings.WandMana)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (!Target.CanDebuffTarget(dpsSpell)) return false;
                if (!Target.IsElite && !Target.IsHealthPercentAbove(30)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class HolyFire : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Holy Fire";
                Spell.Cast(dpsSpell);
                Utils.LagSleep();

                bool result = Target.IsDebuffOnTarget(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Psychic Scream
        public class NeedToPsychicScream : Decorator
        {
            public NeedToPsychicScream(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Psychic Scream";

                if (!CLC.ResultOK(PriestSettings.PsychicScream)) return false;

                if (!PriestSettings.ShadowWordDeath.Contains("when in battleground"))
                    if (PriestSettings.PartyHealWhen.Contains("dedicated healer") && (Me.IsInInstance || Utils.IsBattleground) && PriestSettings.PartyHealWhenSpec.Contains(ClassHelpers.Priest.ClassSpec.ToString())) return false;
                if (!Self.IsPowerPercentAbove(PriestSettings.ReserveMana)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (Target.IsDistanceMoreThan(8)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class PsychicScream : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Psychic Scream";
                bool result = Spell.Cast(dpsSpell);
                Utils.LagSleep();

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Chastise

        public class NeedToChastise : Decorator
        {
            public NeedToChastise(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Chastise";

                if (!CLC.ResultOK(PriestSettings.Chastise)) return false;
                if (PriestSettings.PartyHealWhen.Contains("dedicated healer") && (Me.IsInInstance || Utils.IsBattleground) && PriestSettings.PartyHealWhenSpec.Contains(ClassHelpers.Priest.ClassSpec.ToString())) return false;
                if (!Self.IsPowerPercentAbove(PriestSettings.ReserveMana)) return false;
                if (!Self.IsPowerPercentAbove(PriestSettings.WandMana)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class Chastise : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Chastise";
                bool result = Spell.Cast(dpsSpell);
                Utils.LagSleep();

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }

        #endregion

        #region Smite
        public class NeedToSmite : Decorator
        {
            public NeedToSmite(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Smite";

                if (!PriestSettings.Smite.Contains("when in battleground"))
                    if (PriestSettings.PartyHealWhen.Contains("dedicated healer") && (Me.IsInInstance || Utils.IsBattleground) && PriestSettings.PartyHealWhenSpec.Contains(ClassHelpers.Priest.ClassSpec.ToString())) return false;
                if (!Self.IsPowerPercentAbove(PriestSettings.WandMana)) return false;
                if (!CLC.ResultOK(PriestSettings.Smite)) return false;
                if (!Self.IsPowerPercentAbove(PriestSettings.ReserveMana)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class Smite : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Smite";
                bool swdcd = Spell.IsOnCooldown("Shadow Word: Death");

                bool result = Spell.Cast(dpsSpell);
                Utils.LagSleep();

                if (PriestSettings.ShadowWordDeath.Contains("target < 25%") && Spell.IsKnown("Shadow Word: Death") && !swdcd)
                {
                    while (Me.IsCasting)
                    {
                        ObjectManager.Update();
                        if (Target.HealthPercent < 26)
                        {
                            Spell.StopCasting();
                            while (Spell.IsGCD) Thread.Sleep(250);
                            Utils.Log("-Interrupting Smite to cast Shadow Word: Death - PEW PEW PEW!", Utils.Colour("Red"));
                            Spell.Cast("Shadow Word: Death");
                            return RunStatus.Success;
                        }
                    }
                }

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region healing

        #region Penance
        public class NeedToPenance : Decorator
        {
            public NeedToPenance(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Penance";

                if (!CLC.ResultOK(PriestSettings.Penance)) return false;
                if (!PriestSettings.Penance.Contains("when in battleground"))
                    if (PriestSettings.PartyHealWhen.Contains("dedicated healer") && (Me.IsInInstance || Utils.IsBattleground) && PriestSettings.PartyHealWhenSpec.Contains(ClassHelpers.Priest.ClassSpec.ToString())) return false;
                if (!Self.IsPowerPercentAbove(PriestSettings.ReserveMana)) return false;
                if (!Self.IsPowerPercentAbove(PriestSettings.WandMana)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class Penance : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Penance";
                bool result = Spell.Cast(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Archangle (Solo / Questing)
        public class NeedToArchangle : Decorator
        {
            public NeedToArchangle(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Archangel";

                if (!Me.ActiveAuras.ContainsKey("Evangelism")) return false;
                if ((Me.IsInInstance || Utils.IsBattleground) && !CLC.ResultOK(PriestSettings.ArchangelParty)) return false;
                if ((!Me.IsInInstance && !Utils.IsBattleground) && !CLC.ResultOK(PriestSettings.Archangel)) return false;

                if (Me.IsCasting) return false;
                if (!Spell.CanCastLUA(dpsSpell)) return false; // Using LUA because the normal method fails

                //Utils.Log("********************** this... is... it!");
                const string spell = "Evangelism";
                const string archangle = "Archangel";
                double getTime = Convert.ToDouble(Self.GetTimeLUA());
                double buffTime = Convert.ToDouble(Self.BuffTimeLeftLUA(spell));
                double secondsRemaining = buffTime - getTime;

                if (secondsRemaining < 4.5 && Spell.CanCastLUA(archangle))
                {
                    Lib.LogBlueMessage("Evangelism buff about to expire. Casting Archangel buff to consume it");
                    return true;
                }

                if (Me.ActiveAuras.ContainsKey("Archangel")) return false;
                return (Spell.CanCastLUA(dpsSpell));
            }
        }

        public class Archangle : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Archangel";
                bool result = Spell.Cast(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Heal Pets
        public class NeedToHealPets : Decorator
        {
            public NeedToHealPets(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Flash Heal";

                if (!CLC.ResultOK(PriestSettings.HealPets)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (!Self.IsPowerPercentAbove(40)) return false;

                // Party members with pets, and pets need healing, and can cast spell - return true
                return Me.PartyMembers.Any(p => p.GotAlivePet && (p.Pet.HealthPercent < PriestSettings.RenewHealth || p.Pet.HealthPercent < PriestSettings.FlashHealHealth)) && Spell.CanCast(dpsSpell);
            }
        }

        public class HealPets : Action
        {
            protected override RunStatus Run(object context)
            {
                bool result = false;
                foreach (WoWPlayer p in Me.PartyMembers.Where(p => p.GotAlivePet && (p.Pet.HealthPercent < PriestSettings.RenewHealth || p.Pet.HealthPercent < PriestSettings.FlashHealHealth)))
                {
                    result = ClassHelpers.Priest.PartyHealer(p.Pet);
                    if (result) break;
                }

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Party Decurse
        public class NeedToPartyDecurse : Decorator
        {
            public NeedToPartyDecurse(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Dispel Magic";

                if (!CLC.ResultOK(PriestSettings.PartyCleanse)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (!Me.IsInMyParty && !Me.IsInRaid) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class PartyDecurse : Action
        {
            protected override RunStatus Run(object context)
            {
                bool result = false;

                // Dispel Magic - You and all party members);
                if (!PriestSettings.PartyCleanse.Contains("never") && Spell.CanCast("Dispel Magic"))
                {
                    List<int> urgentRemoval = new List<int> { 17173 };
                    bool urgentCleanse = (from aura in Me.ActiveAuras from procID in urgentRemoval where procID == aura.Value.SpellId select aura).Any();

                    if (urgentCleanse || CLC.ResultOK(PriestSettings.PartyCleanse))
                    {
                        List<WoWDispelType> cureableList = new List<WoWDispelType> { WoWDispelType.Magic };
                        var p = ClassHelpers.Common.DecursePlayer(cureableList, true);
                        if (p != null) { if (Spell.CanCast("Dispel Magic")) { result = Spell.Cast("Dispel Magic", p); } }
                    }
                }

                // Cure Disease - You and all party members);
                if (!PriestSettings.PartyCleanse.Contains("never") && Spell.CanCast("Cure Disease"))
                {
                    List<int> urgentRemoval = new List<int> { 3427 };
                    bool urgentCleanse = (from aura in Me.ActiveAuras from procID in urgentRemoval where procID == aura.Value.SpellId select aura).Any();

                    if (urgentCleanse || CLC.ResultOK(PriestSettings.PartyCleanse))
                    {
                        List<WoWDispelType> cureableList = new List<WoWDispelType> { WoWDispelType.Disease };
                        var p = ClassHelpers.Common.DecursePlayer(cureableList, true);
                        if (p != null) { if (Spell.CanCast("Cure Disease")) result = Spell.Cast("Cure Disease", p); }
                    }
                }

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Party Healer
        public class NeedToPartyHealer : Decorator
        {
            public NeedToPartyHealer(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                if (!Me.IsInParty && !Me.IsInRaid) return false;
                if (PriestSettings.PartyHealWhen.Contains("never")) return false;
                if (!Utils.CombatCheckOk("Flash Heal", false)) return false;
                if (PriestSettings.PartyHealWhen.Contains("OOM or Dead"))
                {
                    WoWUnit healer = RAF.PartyHealerRole;
                    if (healer != null && (healer.Dead || healer.IsGhostVisible)) return true;
                    if (healer != null && healer.ManaPercent < PriestSettings.PartyHealerOOM) return true;

                    return false;
                }

                return true;
            }
        }

        public class PartyHealer : Action
        {
            protected override RunStatus Run(object context)
            {
                WoWUnit healer = RAF.PartyHealerRole;
                WoWUnit tank = RAF.PartyTankRole;

                // Circle of Healing
                int coHCount = Convert.ToInt16(PriestSettings.CircleOfHealingCount);
                List<WoWPlayer> myPartyOrRaidGroup = Me.PartyMembers;
                List<WoWPlayer> coH = (from o in myPartyOrRaidGroup let p = o.ToPlayer() where p.Distance < 40 && !p.Dead && !p.IsGhost && p.InLineOfSight && p.HealthPercent < PriestSettings.CircleOfHealingHealth orderby p.HealthPercent ascending select p).ToList();
                if (coH.Count >= coHCount && Spell.CanCast("Circle of Healing"))
                {
                    Spell.Cast("Circle of Healing", coH[0]);
                    Utils.LagSleep();
                    Utils.WaitWhileCasting();
                    return RunStatus.Success;
                }

                // Heal the almighty Tank - But only if we don't have any urgent heals and tank > 80
                if (tank != null && !tank.Dead)
                {
                    double urgentHealth = tank.HealthPercent * 0.60f;
                    WoWUnit urgentHealTarget = RAF.HealPlayer((int)urgentHealth, 40);
                    if (urgentHealTarget != null && tank.HealthPercent > 80)
                    {
                        Utils.Log(string.Format("-Urgent heal required on {0}, prioritizing over the tank", urgentHealTarget.Class), Utils.Colour("Red"));
                        ClassHelpers.Priest.PartyHealer(urgentHealTarget);
                    }

                    bool result = ClassHelpers.Priest.PartyHealer(tank);
                    if (result) return RunStatus.Success;
                }

                // Prayer of Healing
                int poHCount = Convert.ToInt16(PriestSettings.PrayerOfHealingCount);
                List<WoWPlayer> partyMembers = Me.PartyMembers;
                List<WoWPlayer> poH = (from o in partyMembers let p = o.ToPlayer() where p.Distance < 30 && !p.Dead && !p.IsGhost && p.InLineOfSight && p.HealthPercent < PriestSettings.PrayerOfHealingHealth select p).ToList();
                if (poH.Count >= poHCount && Spell.CanCast("Prayer of Healing"))
                {
                    if (Spell.CanCast("Inner Focus") && !Self.IsBuffOnMe("Inner Focus")) { Spell.Cast("Inner Focus"); Thread.Sleep(500); }
                    Spell.Cast("Prayer of Healing");
                    Utils.LagSleep();
                    Utils.WaitWhileCasting();
                    return RunStatus.Success;
                }

                // Heal Me
                if (Me != null && !Me.Dead)
                {
                    bool result = ClassHelpers.Priest.PartyHealer(Me);
                    if (result) return RunStatus.Success;
                }

                // Party healer
                if (healer != null && !healer.Dead && healer != Me)
                {
                    bool result = ClassHelpers.Priest.PartyHealer(healer);
                    if (result) return RunStatus.Success;
                }

                // Crude way to get the upper value of all PriestSettings
                List<int> healthValues = new List<int> { PriestSettings.PartyGuardianSpirit, PriestSettings.PartyPrayerOfMending, PriestSettings.PartyPenance, PriestSettings.PartyPainSuppression, PriestSettings.PartyPWS, PriestSettings.PartyRenew, PriestSettings.PartyFlashHeal, PriestSettings.PartyGreaterHeal };
                healthValues.Sort();
                int upperHealthValue = healthValues[healthValues.Count - 1];


                // Everyone else in the party gets healed
                bool everyoneResult = false;
                WoWUnit healTarget = RAF.HealPlayer(upperHealthValue, 50);
                if (healTarget != null && !healTarget.Dead)
                {
                    everyoneResult = ClassHelpers.Priest.PartyHealer(healTarget);
                }

                return everyoneResult ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Party Healer UHS
        public class NeedToPartyHealerUHS : Decorator
        {
            public NeedToPartyHealerUHS(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                bool result = false;
                if (!Me.IsInParty && !Me.IsInRaid) return false;
                if (PriestSettings.PartyHealWhen.Contains("never")) return false;
                if (!Utils.CombatCheckOk("Flash Heal", false)) return false;
                if (PriestSettings.PartyHealWhen.Contains("OOM or Dead"))
                {
                    WoWUnit healer = RAF.PartyHealerRole;
                    if (healer != null && (healer.Dead || healer.IsGhostVisible)) result = true;
                    if (healer != null && healer.ManaPercent < PriestSettings.PartyHealerOOM) result = true;
                }

                if (PriestSettings.PartyHealWhen.Contains("dedicated healer") && (Me.IsInInstance || Me.IsInRaid || Utils.IsBattleground) && PriestSettings.PartyHealWhenSpec.Contains(ClassHelpers.Priest.ClassSpec.ToString())) result = true;

                if (result)
                {
                    // Clear everything out
                    HealBot.UHS.Clear();

                    // Populate the UHS
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Circle of Healing", Priority = 0, MaximumDistance = 40, EvaluateBeforeTank = true, IsAoE = true, HealthPercent = PriestSettings.CircleOfHealingHealth, MinimumAoECount = Convert.ToInt16(PriestSettings.CircleOfHealingCount) });
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Guardian Spirit", Priority = 0, MaximumDistance = 40, HealthPercent = PriestSettings.PartyGuardianSpirit });
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Prayer of Mending", Priority = 10, MaximumDistance = 40, HealthPercent = PriestSettings.PartyPrayerOfMending, IsBuff = true });
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Power Word: Shield", Priority = 30, MaximumDistance = 40, HealthPercent = PriestSettings.PartyPWS, IsBuff = true, OtherDebuffs = "Weakened Soul", MinimumMobAggroCount = 1 });
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Penance", Priority = 50, MaximumDistance = 40, HealthPercent = PriestSettings.PartyPenance });
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Pain Suppression", Priority = 60, MaximumDistance = 40, HealthPercent = PriestSettings.PartyPainSuppression, IsBuff = true });
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Prayer of Healing", MaximumDistance = 40, Priority = 70, IsAoE = true, HealthPercent = PriestSettings.PrayerOfHealingHealth, MinimumAoECount = Convert.ToInt16(PriestSettings.PrayerOfHealingCount) });
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Renew", IncludePets = true, Priority = 80, MaximumDistance = 40, HealthPercent = PriestSettings.PartyRenew, IsBuff = true });
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Flash Heal", IncludePets = true, MaximumDistance = 40, Priority = 90, HealthPercent = PriestSettings.PartyFlashHeal });
                    HealBot.UHS.Add(new HealBot.HealingSpell { SpellName = "Greater Heal", MaximumDistance = 40, Priority = 100, HealthPercent = PriestSettings.PartyGreaterHeal });

                    // Sort spells based on priority
                    HealBot.Sort();

                    // Is it ok to heal pets?
                    HealBot.HealPets = PriestSettings.HealPets.Contains("always");
                }


                return result;
            }
        }

        public class PartyHealerUHS : Action
        {
            protected override RunStatus Run(object context)
            {
                bool result = HealBot.Heal();

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region BouncePOM
        public class NeedToBouncePOM : Decorator
        {
            public NeedToBouncePOM(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Shadow Word: Death";

                if (!CLC.ResultOK(PriestSettings.BouncePoM)) return false;
                if (!Self.IsBuffOnMe("Prayer of Mending")) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class BouncePOM : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Shadow Word: Death";
                bool result = Spell.Cast(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Wand Party
        public class NeedToWandParty : Decorator
        {
            public NeedToWandParty(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Shoot";

                if ((Me.IsInInstance || Utils.IsBattleground) && PriestSettings.PartyHealWhen.Contains("dedicated"))
                {
                    if (!Me.IsInParty) return false;
                    if (!CLC.ResultOK(PriestSettings.WandParty)) return false;
                    if (!Me.GotTarget) return false;
                    if (!Me.CurrentTarget.InLineOfSpellSight) return false;
                    if (Target.IsDistanceMoreThan(30)) return false;
                    if (Spell.IsGCD || Me.IsCasting) return false;
                    if (!Utils.IsNotWanding) return false;
                    if (RAF.HealPlayer(PriestSettings.SmiteEvangelismHealth, 50) != null) return false;
                }
                else
                {
                    if (!Me.GotTarget) return false;
                    if (Self.IsPowerPercentAbove(PriestSettings.WandMana)) return false;
                    if (!Me.CurrentTarget.InLineOfSpellSight) return false;
                    if (Target.IsDistanceMoreThan(30)) return false;
                    if (Spell.IsGCD || Me.IsCasting) return false;
                    if (!Utils.IsNotWanding) return false;
                }


                return (Spell.CanCast(dpsSpell));
            }
        }

        public class WandParty : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Shoot";
                Spell.Cast(dpsSpell);

                return RunStatus.Failure;
            }
        }
        #endregion

        #region Power Word: Barrier
        public class NeedToPowerWordBarrier : Decorator
        {
            public NeedToPowerWordBarrier(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Power Word: Barrier";

                if (!CLC.ResultOK(PriestSettings.PowerWordBarrier)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class PowerWordBarrier : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Power Word: Barrier";
                Spell.Cast(dpsSpell, Me.Location);
                //System.Threading.Thread.Sleep(500);



                return RunStatus.Success;
            }
        }
        #endregion

        #region Hymn of Hope
        public class NeedToHymnOfHope : Decorator
        {
            public NeedToHymnOfHope(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Hymn of Hope";

                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (Self.IsPowerPercentAbove(PriestSettings.HymnOfHopeMana)) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class HymnOfHope : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Hymn of Hope";
                bool result = Spell.Cast(dpsSpell);
                Utils.LagSleep();
                Utils.WaitWhileCasting();

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Smite Evangelism
        public class NeedToSmiteEvangelism : Decorator
        {
            public NeedToSmiteEvangelism(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Smite";

                if (!Me.GotTarget) return false;
                if (!Timers.Expired("ArcSmiteCombat", 2500)) return false;
                if (!Me.IsInInstance && !Utils.IsBattleground) return false;
                if (PriestSettings.SmiteEvangelism.Contains("never")) return false;
                if (Target.IsDistanceMoreThan(30)) return false;
                if (Target.HealthPercent < 35) return false;
                if (PriestSettings.SmiteEvangelism.Contains("90%") && !Self.IsPowerPercentAbove(90)) return false;
                if (PriestSettings.SmiteEvangelism.Contains("85%") && !Self.IsPowerPercentAbove(85)) return false;
                if (PriestSettings.SmiteEvangelism.Contains("80%") && !Self.IsPowerPercentAbove(80)) return false;
                if (PriestSettings.SmiteEvangelism.Contains("75%") && !Self.IsPowerPercentAbove(75)) return false;
                if (PriestSettings.SmiteEvangelism.Contains("70%") && !Self.IsPowerPercentAbove(70)) return false;
                if (PriestSettings.SmiteEvangelism.Contains("65%") && !Self.IsPowerPercentAbove(65)) return false;
                if (PriestSettings.SmiteEvangelism.Contains("60%") && !Self.IsPowerPercentAbove(60)) return false;
                if (PriestSettings.SmiteEvangelism.Contains("55%") && !Self.IsPowerPercentAbove(55)) return false;
                if (PriestSettings.SmiteEvangelism.Contains("50%") && !Self.IsPowerPercentAbove(50)) return false;
                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (RAF.HealPlayer(PriestSettings.SmiteEvangelismHealth, 50) != null) return false;

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class SmiteEvangelism : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Smite";
                bool result = Spell.Cast(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion

        #region Chakra
        public class NeedToChakra : Decorator
        {
            public NeedToChakra(Composite child) : base(child) { }

            protected override bool CanRun(object context)
            {
                const string dpsSpell = "Chakra";

                if (!Utils.CombatCheckOk(dpsSpell, false)) return false;
                if (Self.IsBuffOnMe(81207)) return false;           // Sanctuary
                if (Self.IsBuffOnMe(81208)) return false;           // Serenity
                if (Self.IsBuffOnMe(81209)) return false;           // Chastise
                if (Self.IsBuffOnMe(dpsSpell)) return false;        // Chakra

                return (Spell.CanCast(dpsSpell));
            }
        }

        public class Chakra : Action
        {
            protected override RunStatus Run(object context)
            {
                const string dpsSpell = "Chakra";
                bool result = Spell.Cast(dpsSpell);

                return result ? RunStatus.Success : RunStatus.Failure;
            }
        }
        #endregion



        #endregion



        public static void ShadowPriestClassPulse()
        {
            //int lootableMobs = LootTargeting.Instance.LootingList.Count;

            // If PriestSettings.DirtyData = true it will reload the settings from the XML file
            // This reads the XML file and re-populates the PriestSettings class with any changed values
            if (!AkatoshCore.Instance._isCCLoaded) { AkatoshCore.Instance._isCCLoaded = true; PriestSettings.DirtyData = true; }
            if (PriestSettings.DirtyData) AkatoshCore.Instance.LoadSettings(true);

            // So we don't overload HB the below code is only run once per second
            if (!Timers.Expired("Pulse", 1000)) return;
            Timers.Recycle("Pulse", 1000);

            // Environmental PriestSettings
            if (Timers.Expired("EnvironmentSettings", 5000))
            {
                if (PriestSettings.MultipleEnvironment.Contains("never"))
                {
                    ConfigSettings.CurrentEnvironment = "PVE";
                }
                else
                {
                    Timers.Reset("EnvironmentSettings");
                    string environment = Utils.IsBattleground ? "PVP" : "PVE";
                    environment = ObjectManager.Me.IsInInstance ? "Instance" : environment;
                    if (!ConfigSettings.UIActive && environment != ConfigSettings.CurrentEnvironment)
                    {
                        ConfigSettings.CurrentEnvironment = environment;
                        Utils.Log(string.Format("*** Environment has changed. Loading {0} settings.", environment), Utils.Colour("Red"));
                        AkatoshCore.Instance.LoadSettings(false);
                    }
                }
            }

            // Evangelism / Archangel 
            if (!Me.Combat) Timers.Reset("ArcSmiteCombat");

            // Make sure we have a target - Instance only
            // Sometimes IB was not selecting a target when we were in combat. This fucked up things immensely!
            if (Me.IsInInstance && !Me.GotTarget)
            {
                WoWUnit tank = RAF.PartyTankRole;
                if (tank != null && tank.GotTarget && tank.Combat) RAF.PartyTankRole.CurrentTarget.Target();
            }


            // Dispel Magic - You and all party members);
            if ((!PriestSettings.Cleanse.Contains("never") || !PriestSettings.PartyCleanse.Contains("never")) && Spell.CanCast("Dispel Magic"))
            {
                var urgentRemoval = new List<int> { 17173 };
                var urgentCleanse = (from aura in Me.ActiveAuras from procID in urgentRemoval where procID == aura.Value.SpellId select aura).Any();

                if (urgentCleanse || CLC.ResultOK(PriestSettings.Cleanse) || CLC.ResultOK(PriestSettings.PartyCleanse))
                {
                    var cureableList = new List<WoWDispelType> { WoWDispelType.Magic };
                    //if (PriestSettings.SacredCleansing.Contains("... talented") && !cureableList.Contains(WoWDispelType.Magic)) { cureableList.Add(WoWDispelType.Magic); }

                    var p = ClassHelpers.Common.DecursePlayer(cureableList, CLC.ResultOK(PriestSettings.PartyCleanse));
                    if (p != null)
                    {
                        if (Spell.CanCast("Dispel Magic")) Spell.Cast("Dispel Magic", p);
                    }
                }
            }

            // Cure Disease - You and all party members);
            if ((!PriestSettings.Cleanse.Contains("never") || !PriestSettings.PartyCleanse.Contains("never")) && Spell.CanCast("Cure Disease"))
            {
                var urgentRemoval = new List<int> { 3427 };
                bool urgentCleanse = (from aura in Me.ActiveAuras from procID in urgentRemoval where procID == aura.Value.SpellId select aura).Any();

                if (urgentCleanse || CLC.ResultOK(PriestSettings.Cleanse))
                {
                    var cureableList = new List<WoWDispelType> { WoWDispelType.Disease };
                    var p = ClassHelpers.Common.DecursePlayer(cureableList, CLC.ResultOK(PriestSettings.PartyCleanse));
                    if (p != null) { if (Spell.CanCast("Cure Disease")) Spell.Cast("Cure Disease", p); }
                }
            }

            // Buffs and such
            if (!Me.IsFlying && !Me.Mounted && !Me.IsOnTransport && !Me.Auras.ContainsKey("Altered Form"))
            {
                // Inner Fire/Will
                if (!Self.IsBuffOnMe("Inner Fire") && PriestSettings.InnerFireWill.Contains("Inner Fire") && Spell.CanCast("Inner Fire")) Spell.Cast("Inner Fire", Me);
                if (!Self.IsBuffOnMe("Inner Will") && PriestSettings.InnerFireWill.Contains("Inner Will") && Spell.CanCast("Inner Will")) Spell.Cast("Inner Will", Me);

                // Power Word Fortitude
                if (Me.IsInParty && !Me.Combat && CLC.ResultOK(PriestSettings.PowerWordFortitude) && Spell.CanCast("Power Word: Fortitude"))
                {
                    const string buffName = "Power Word: Fortitude";
                    WoWUnit target = RAF.PartyMemberWithoutBuff(buffName);
                    if (target != null && !target.Auras.ContainsKey("Blood Pact")) Spell.Cast(buffName, target);
                }
                if (!Me.IsInParty && !Me.Combat && !Self.IsBuffOnMe("Power Word: Fortitude") && CLC.ResultOK(PriestSettings.PowerWordFortitude) && Spell.CanCast("Power Word: Fortitude")) Spell.Cast("Power Word: Fortitude", Me);

                // Shadow Protection
                if (Me.IsInParty && !Me.Combat && CLC.ResultOK(PriestSettings.ShadowProtection) && Spell.CanCast("Shadow Protection"))
                {
                    const string buffName = "Shadow Protection";
                    WoWUnit target = RAF.PartyMemberWithoutBuff(buffName);
                    if (target != null) Spell.Cast(buffName, target);
                }
                if (!Me.IsInParty && !Me.Combat && !Self.IsBuffOnMe("Shadow Protection") && CLC.ResultOK(PriestSettings.ShadowProtection) && Spell.CanCast("Shadow Protection")) Spell.Cast("Shadow Protection", Me);

                // Vampiric Embrace
                if (!Self.IsBuffOnMe("Vampiric Embrace") && Spell.CanCast("Vampiric Embrace")) Spell.Cast("Vampiric Embrace");

                // Fear Ward
                if (!Self.IsBuffOnMe("Fear Ward") && CLC.ResultOK(PriestSettings.FearWard) && Spell.CanCast("Fear Ward")) Spell.Cast("Fear Ward", Me);
            }

            // Shadowform - can be applied while flying and mounted
            //if (CLC.ResultOK(PriestSettings.Shadowform) && !Self.IsBuffOnMe("Shadowform") && Self.IsHealthPercentAbove(PriestSettings.RenewHealth) && Spell.CanCast("Shadowform")) Spell.Cast("Shadowform");
            if (CLC.ResultOK(PriestSettings.Shadowform) && !Self.IsBuffOnMe(15473, Self.AuraCheck.AllAuras) && !Me.Mounted && Self.IsHealthPercentAbove(PriestSettings.RenewHealth) && Spell.CanCast("Shadowform")) Spell.Cast("Shadowform");


            


            // Archangel - Use it or loose it
            if (!Me.Mounted && !Me.IsFlying && (!Me.Auras.ContainsKey("Drink") || !Me.Auras.ContainsKey("Food")) && Me.ActiveAuras.ContainsKey("Evangelism") && !Me.Combat)
            {
                const string spell = "Evangelism";
                const string archangel = "Archangel";
                double getTime = Convert.ToDouble(Self.GetTimeLUA());
                double buffTime = Convert.ToDouble(Self.BuffTimeLeftLUA(spell));
                double secondsRemaining = buffTime - getTime;

                if (secondsRemaining < 4.5 && Spell.CanCastLUA(archangel))
                {
                    Lib.LogBlueMessage("Evangelism buff about to expire. Casting Archangel buff to consume it");
                    Spell.Cast(archangel);
                }
            }


            // Resurrection
            if (PriestSettings.ResurrectPlayers.Contains("always") && !Me.Combat && Spell.CanCast("Resurrection") && !Me.IsCasting && Me.IsInInstance && !Utils.IsBattleground)
            {
                foreach (WoWPlayer p in Me.PartyMembers.Where(p => p.Dead && !p.IsGhost && p.InLineOfSpellSight))
                {
                    if (Timers.Exists(p.Guid.ToString(CultureInfo.InvariantCulture)) && !Timers.Expired(p.Guid.ToString(CultureInfo.InvariantCulture), 15000)) continue;

                    Spell.Cast("Resurrection", p);
                    Utils.LagSleep();
                    Timers.Add(p.Guid.ToString(CultureInfo.InvariantCulture));  // Prevent spamming resurrection on th same target
                    Thread.Sleep(1500);
                    if (!Me.IsCasting) Spell.StopCasting();
                    while (Me.IsCasting)
                    {
                        if (!p.Dead)
                        {
                            Lib.LogBlueMessage("-Emmm.... it appears our dead party member is now alive. So why are we still trying to rez them?");
                            Spell.StopCasting();
                        }
                    }
                    break;
                }
            }

            // Clean up timers
            foreach (WoWPlayer p in Me.PartyMembers.Where(p => p.IsAlive && Timers.Exists(p.Guid.ToString(CultureInfo.InvariantCulture))))
            {
                Timers.Remove(p.Guid.ToString(CultureInfo.InvariantCulture));
            }
        }

        public static void DiscPriestClassPulse()
        {
            // If PriestSettings.DirtyData = true it will reload the settings from the XML file
            // This reads the XML file and re-populates the PriestSettings class with any changed values
            if (!AkatoshCore.Instance._isCCLoaded) { AkatoshCore.Instance._isCCLoaded = true; PriestSettings.DirtyData = true; }
            if (PriestSettings.DirtyData) AkatoshCore.Instance.LoadSettings(true);

            // So we don't overload HB the below code is only run once per second
            if (!Timers.Expired("Pulse", 1000)) return;
            Timers.Recycle("Pulse", 1000);

            // Environmental PriestSettings
            if (Timers.Expired("EnvironmentSettings", 5000))
            {
                if (PriestSettings.MultipleEnvironment.Contains("never"))
                {
                    ConfigSettings.CurrentEnvironment = "PVE";
                }
                else
                {
                    Timers.Reset("EnvironmentSettings");
                    string environment = Utils.IsBattleground ? "PVP" : "PVE";
                    environment = ObjectManager.Me.IsInInstance ? "Instance" : environment;
                    if (!ConfigSettings.UIActive && environment != ConfigSettings.CurrentEnvironment)
                    {
                        ConfigSettings.CurrentEnvironment = environment;
                        Utils.Log(string.Format("*** Environment has changed. Loading {0} settings.", environment), Utils.Colour("Red"));
                        AkatoshCore.Instance.LoadSettings(false);
                    }
                }
            }

            // Evangelism / Archangel 
            if (!Me.Combat) Timers.Reset("ArcSmiteCombat");

            // Make sure we have a target - Instance only
            // Sometimes IB was not selecting a target when we were in combat. This fucked up things immensely!
            if (Me.IsInInstance && !Me.GotTarget)
            {
                WoWUnit tank = RAF.PartyTankRole;
                if (tank != null && tank.GotTarget && tank.Combat) RAF.PartyTankRole.CurrentTarget.Target();
            }


            // Dispel Magic - You and all party members);
            if ((!PriestSettings.Cleanse.Contains("never") || !PriestSettings.PartyCleanse.Contains("never")) && Spell.CanCast("Dispel Magic"))
            {
                List<int> urgentRemoval = new List<int> { 17173 };
                bool urgentCleanse = (from aura in Me.ActiveAuras from procID in urgentRemoval where procID == aura.Value.SpellId select aura).Any();

                if (urgentCleanse || CLC.ResultOK(PriestSettings.Cleanse) || CLC.ResultOK(PriestSettings.PartyCleanse))
                {
                    List<WoWDispelType> cureableList = new List<WoWDispelType> { WoWDispelType.Magic };
                    //if (PriestSettings.SacredCleansing.Contains("... talented") && !cureableList.Contains(WoWDispelType.Magic)) { cureableList.Add(WoWDispelType.Magic); }

                    var p = ClassHelpers.Common.DecursePlayer(cureableList, CLC.ResultOK(PriestSettings.PartyCleanse));
                    if (p != null)
                    {
                        if (Spell.CanCast("Dispel Magic")) Spell.Cast("Dispel Magic", p);
                    }
                }
            }

            // Cure Disease - You and all party members);
            if ((!PriestSettings.Cleanse.Contains("never") || !PriestSettings.PartyCleanse.Contains("never")) && Spell.CanCast("Cure Disease"))
            {
                List<int> urgentRemoval = new List<int> { 3427 };
                bool urgentCleanse = (from aura in Me.ActiveAuras from procID in urgentRemoval where procID == aura.Value.SpellId select aura).Any();

                if (urgentCleanse || CLC.ResultOK(PriestSettings.Cleanse))
                {
                    List<WoWDispelType> cureableList = new List<WoWDispelType> { WoWDispelType.Disease };
                    var p = ClassHelpers.Common.DecursePlayer(cureableList, CLC.ResultOK(PriestSettings.PartyCleanse));
                    if (p != null) { if (Spell.CanCast("Cure Disease")) Spell.Cast("Cure Disease", p); }
                }
            }

            // Buffs and such
            if (!Me.IsFlying && !Me.Mounted && !Me.Auras.ContainsKey("Altered Form"))
            {
                // Inner Fire/Will
                if (!Self.IsBuffOnMe("Inner Fire") && PriestSettings.InnerFireWill.Contains("Inner Fire") && Spell.CanCast("Inner Fire")) Spell.Cast("Inner Fire", Me);
                if (!Self.IsBuffOnMe("Inner Will") && PriestSettings.InnerFireWill.Contains("Inner Will") && Spell.CanCast("Inner Will")) Spell.Cast("Inner Will", Me);

                // Power Word Fortitude
                if (Me.IsInParty && !Me.Combat && CLC.ResultOK(PriestSettings.PowerWordFortitude) && Spell.CanCast("Power Word: Fortitude"))
                {
                    const string buffName = "Power Word: Fortitude";
                    WoWUnit target = RAF.PartyMemberWithoutBuff(buffName);
                    if (target != null && !target.Auras.ContainsKey("Blood Pact")) Spell.Cast(buffName, target);
                }
                if (!Me.IsInParty && !Me.Combat && !Self.IsBuffOnMe("Power Word: Fortitude") && CLC.ResultOK(PriestSettings.PowerWordFortitude) && Spell.CanCast("Power Word: Fortitude")) Spell.Cast("Power Word: Fortitude", Me);

                // Shadow Protection
                if (Me.IsInParty && !Me.Combat && CLC.ResultOK(PriestSettings.ShadowProtection) && Spell.CanCast("Shadow Protection"))
                {
                    const string buffName = "Shadow Protection";
                    WoWUnit target = RAF.PartyMemberWithoutBuff(buffName);
                    if (target != null) Spell.Cast(buffName, target);
                }
                if (!Me.IsInParty && !Me.Combat && !Self.IsBuffOnMe("Shadow Protection") && CLC.ResultOK(PriestSettings.ShadowProtection) && Spell.CanCast("Shadow Protection")) Spell.Cast("Shadow Protection", Me);

                // Vampiric Embrace
                if (!Self.IsBuffOnMe("Vampiric Embrace") && Spell.CanCast("Vampiric Embrace")) Spell.Cast("Vampiric Embrace");

                // Fear Ward
                if (!Self.IsBuffOnMe("Fear Ward") && CLC.ResultOK(PriestSettings.FearWard) && Spell.CanCast("Fear Ward")) Spell.Cast("Fear Ward", Me);
            }

            // Shadowform - can be applied while flying and mounted
            //if (CLC.ResultOK(PriestSettings.Shadowform) && !Self.IsBuffOnMe("Shadowform") && Self.IsHealthPercentAbove(PriestSettings.RenewHealth) && Spell.CanCast("Shadowform")) Spell.Cast("Shadowform");
            if (CLC.ResultOK(PriestSettings.Shadowform) && !Self.IsBuffOnMe(15473, Self.AuraCheck.AllAuras) && !Me.Mounted && Self.IsHealthPercentAbove(PriestSettings.RenewHealth) && Spell.CanCast("Shadowform")) Spell.Cast("Shadowform");


            // Prayer of Healing
            if (!Me.Mounted && !Me.IsFlying && !Me.Combat && (Me.IsInParty || Me.IsInRaid))
            {
                int poHCount = Convert.ToInt16(PriestSettings.PrayerOfHealingCount);
                List<WoWPlayer> myPartyOrRaidGroup = Me.PartyMembers;
                List<WoWPlayer> poH = (from o in myPartyOrRaidGroup let p = o.ToPlayer() where p.Distance < 30 && !p.Dead && !p.IsGhost && p.InLineOfSight && p.HealthPercent < PriestSettings.PrayerOfHealingHealth select p).ToList();
                if (poH.Count >= poHCount && Spell.CanCast("Prayer of Healing"))
                {
                    Spell.Cast("Prayer of Healing");
                    Utils.LagSleep();
                    Utils.WaitWhileCasting();
                }

                // Everyone else in the party gets healed
                WoWUnit healTarget = RAF.HealPlayer(95, 40);
                if (healTarget != null && !healTarget.Dead) ClassHelpers.Priest.PartyHealer(healTarget);
            }


            // Archangel - Use it or loose it
            if (!Me.Mounted && !Me.IsFlying && (!Me.Auras.ContainsKey("Drink") || !Me.Auras.ContainsKey("Food")) && Me.ActiveAuras.ContainsKey("Evangelism") && !Me.Combat)
            {
                const string spell = "Evangelism";
                const string archangel = "Archangel";
                double getTime = Convert.ToDouble(Self.GetTimeLUA());
                double buffTime = Convert.ToDouble(Self.BuffTimeLeftLUA(spell));
                double secondsRemaining = buffTime - getTime;

                if (secondsRemaining < 4.5 && Spell.CanCastLUA(archangel))
                {
                    Utils.Log("-Evangelism buff about to expire. Casting Archangel buff to consume it", Utils.Colour("Red"));
                    Spell.Cast(archangel);
                }
            }


            // Resurrection
            if (PriestSettings.ResurrectPlayers.Contains("always") && !Me.Combat && Spell.CanCast("Resurrection") && !Me.IsCasting)
            {
                foreach (WoWPlayer p in Me.PartyMembers.Where(p => p.Dead && !p.IsGhost && p.InLineOfSight))
                {
                    if (Timers.Exists(p.Guid.ToString(CultureInfo.InvariantCulture)) && !Timers.Expired(p.Guid.ToString(CultureInfo.InvariantCulture), 15000)) continue;

                    Spell.Cast("Resurrection", p);
                    Utils.LagSleep();
                    Timers.Add(p.Guid.ToString(CultureInfo.InvariantCulture));  // Prevent spamming resurrection on th same target
                    Thread.Sleep(1500);
                    if (!Me.IsCasting) Spell.StopCasting();
                    while (Me.IsCasting)
                    {
                        if (!p.Dead)
                        {
                            Utils.Log("-Emmm.... it appears our dead party member is now alive. So why are we still trying to rez them?");
                            Spell.StopCasting();
                        }
                    }
                    break;
                }
            }

            // Clean up timers
            foreach (WoWPlayer p in Me.PartyMembers.Where(p => p.IsAlive && Timers.Exists(p.Guid.ToString(CultureInfo.InvariantCulture))))
            {
                Timers.Remove(p.Guid.ToString(CultureInfo.InvariantCulture));
            }
        }
    }
}